/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/




#if !defined(AFX_PGLGLUTILITY_H__0E205062_3FFE_4548_9974_C5136B8D6580__INCLUDED_)
#define AFX_PGLGLUTILITY_H__0E205062_3FFE_4548_9974_C5136B8D6580__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <pgl/core/PGLColor.h>

/*! \brief Static Miscellanous utilities

\ingroup PGLBasicGroup
*/ 
class PGLCORE_EXT_CLASS CPGLUtility  
{
public:

	//! Peek and pumps message queue
	static void PeekAndPump();

	//! Colormaps
	enum EColorMap
	{
		//! HSV
		ColorMapHsv=0,
		//! Jet
		ColorMapJet=1,
		//! Gray
		ColorMapGray=2,
		//! Pink
		ColorMapPink=3,
		//! Cool
		ColorMapCool=4,
		//! Bone
		ColorMapBone=5,
		//! Copper
		ColorMapCopper=6,
		//! Hot
		ColorMapHot=7,
		//! Autumn
		ColorMapAutumn=8,
		//! Winter
		ColorMapWinter=9,
		//! Spring
		ColorMapSpring=10,
		//! Summer
		ColorMapSummer=11
	};

	/*! \brief Draws the color map

	\todo Implement this method
	*/
	//static void DrawColorMap(gfxinterface::CGfxInterface& gfx, EColorMap eCM, CPGLViewScreen* pView);

	/*! \brief Colormap function

	\param eCM type of color map
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void ColorMap(EColorMap eCM,double alpha, CPGLColor& col);

	/*! \brief Hue-Saturation-Value color map

	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color

		An HSV colormap varies the hue commponent of the hue-saturation-value color model.
		The colors with red, pass trhough yellow, green, cyan, blue, magenta and return
		to red.
	*/
	static void HSV(double alpha, CPGLColor& col);
	/*! \brief Variant of HSV.
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Jet(double alpha, CPGLColor& col);
	/*! \brief Linear ColorMapGray-scale color map
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Gray(double alpha, CPGLColor& col);
	/*! \brief Pastel shades of ColorMapPink color map.
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Pink(double alpha, CPGLColor& col);
	/*! \brief Shades of cyan and magenta color map
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Cool(double alpha, CPGLColor& col);
	/*! \brief Gray-scale with a tinge of blue color map.
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Bone(double alpha, CPGLColor& col);
	/*! \brief Linear ColorMapCopper-tone color map
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Copper(double alpha, CPGLColor& col);
	/*! \brief Black-red-yellow-white color map
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Hot(double alpha, CPGLColor& col);
	/*! \brief Shades of red and yellow color map.
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Autumn(double alpha, CPGLColor& col);
	/*! \brief Shades of blue and green color map.
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Winter(double alpha, CPGLColor& col);
	/*! \brief Shades of magenta and yellow color map.
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Spring(double alpha, CPGLColor& col);
	/*! \brief Shades of green and yellow colormap.
	
	\param alpha normalized parameter in [0,1] (Clipped if out of this interval)
	\param col resulting color
	*/
	static void Summer(double alpha, CPGLColor& col);

	//! returns the string describing the colormap (used in serialization)
	static LPCTSTR ColorMap2String(EColorMap cm);
	//! returns color map enum from string
	static EColorMap String2ColorMap(LPCTSTR str);
};

/*! \name Backward compatibility definition.

\ingroup PGLBasicGroup
*/
//@{
#define PGL_COLORMAP CPGLUtility::EColorMap
#define pglCmHsv CPGLUtility::ColorMapHsv
#define pglCmJet CPGLUtility::ColorMapJet
#define pglCmGray CPGLUtility::ColorMapGray
#define pglCmPink CPGLUtility::ColorMapPink
#define pglCmCool CPGLUtility::ColorMapCool
#define pglCmBone CPGLUtility::ColorMapBone
#define pglCmCopper CPGLUtility::ColorMapCopper
#define pglCmHot CPGLUtility::ColorMapHot
#define pglCmAutumn CPGLUtility::ColorMapAutumn
#define pglCmWinter CPGLUtility::ColorMapWinter
#define pglCmSpring CPGLUtility::ColorMapSpring
#define pglCmSummer CPGLUtility::ColorMapSummer
//@}

/*! \brief Point class template

\ingroup PGLBasicGroup
*/
template <class T> class CPGLPoint
{
public:
	//! Default constructor
	CPGLPoint<T>(T _x=T(), T _y=T())	{	x=_x; y=_y;};
	//! x coordinate
	T x;
	//! y coordinate
	T y;
};

/*! CPGLPoint<double> CPGLPointD
Point of double type

  \ingroup PGLBasicGroup
*/
typedef CPGLPoint<double> CPGLPointD; 
/*! CPGLPoint<int> CPGLPointI
Point of int type
  \ingroup PGLBasicGroup
*/
typedef CPGLPoint<int> CPGLPointI; 
/*! CPGLPoint<UINT> CPGLPointU
Point of UINT type

  \ingroup PGLBasicGroup
*/
typedef CPGLPoint<UINT> CPGLPointU; 
/*! CPGLPoint<bool> CPGLPointB
Point of bool type

  \ingroup PGLBasicGroup
*/
typedef CPGLPoint<bool> CPGLPointB; 

/*! \brief Rect class template

\ingroup PGLBasicGroup
*/
template <class T> class CPGLRect
{
public:

	//! \name Constructors
	//@{
	/*! \brief Default constructor
	
	 \param tLeft left of rect
	 \param tBottom bottom of rect
	 \param tRight right of rect
	 \param tTop top of rect
	*/
	CPGLRect<T>(T tLeft = 0, T tBottom = 0, T tRight = 1, T tTop = 1)	{	left=tLeft; bottom=tBottom; right=tRight; top=tTop;};
	//! Copy constructor
	CPGLRect<T>(const CPGLRect<T>& r)	{*this=r;};
	//! Assignement constructor
	CPGLRect<T>& operator = (const CPGLRect<T>& r) { if (&r!=this)	{	left=r.left; bottom=r.bottom; right=r.right; top=r.top;} return *this;};
	//! returns a normalized box
	static CPGLRect<T> GetNormBox() {	CPGLRect<T> r(0,0,1,1); return r;};
	//@}

	//! \name Attributes
	//@{
	//! left
	T left;
	//! right
	T right;
	//! bottom
	T bottom;
	//! top
	T top;
	//! true if x coordinate has a sense
	bool xValid;
	//! true if y coordinate has a sense
	bool yValid;
	//@}

	//! \name Helpers
	//@{
	//! returns width
	T GetWidth() const						{	return right-left;};
	//! returns height
	T GetHeight() const						{	return top-bottom;};
	//! returns center point
	CPGLPoint<T> GetCenter() const			{	return CPGLPointD( (left+right)/2.0, (bottom+top)/2.0 );};
	//! grows the box to enclose r x coordinates
	void SetUnionX(CPGLRect<T>& r) const	{	r.left = __min(r.left, left); r.right = __max(r.right,right);}; 
	//! grows the box to enclose r y coordinates
	void SetUnionY(CPGLRect<T>& r) const	{	r.bottom = __min(r.bottom, bottom); r.top = __max(r.top,top);}; 
	//! grows the box to enclose r x and y coordinates
	void SetUnion(CPGLRect<T>& r) const		{	r.left = __min(r.left, left); r.right = __max(r.right,right); r.bottom = __min(r.bottom, bottom); r.top = __max(r.top,top);}; 
	//! grows the box to enclose p x coordinates
	void MakeUnionX(const T& p)				{	left = __min(left, p); right = __max(right,p);}; 
	//! grows the box to enclose p y coordinates
	void MakeUnionY(const T& p)				{	bottom = __min(bottom, p); top = __max(top,p);}; 
	//! returns true if empty
	bool IsEmpty() const					{	return ( IsWidthEmpty() || IsHeightEmpty()); };
	//! return true if width empty
	bool IsWidthEmpty() const				{	return algotools::IsGreaterEqual(left,right);};	
	//! return true if width empty
	bool IsHeightEmpty() const				{	return algotools::IsGreaterEqual(bottom,top);};	

	//! return true if point is inside the rect
	bool IsInside( const CPGLPointD& point, bool yDirectionDown = true) const	
	{	
		if (yDirectionDown)
			return ((point.x >= left) && (point.x <= right) && (point.y <= bottom) && (point.y>= top));
		else
			return ((point.x >= left) && (point.x <= right) && (point.y >= bottom) && (point.y<= top));}; 

	//! adds 2 rect
	friend CPGLRect<T> operator + (const CPGLRect<T>& a, const CPGLRect<T>& b)
	{	return CPGLRect<T>(a.left+b.left, a.bottom+b.bottom, a.right+b.right, a.top+b.top);};

	//! Scales rect 
	void Scale(const CPGLPoint<T> sc)
	{	left-=GetWidth()*(sc.x-1)/2.0; right+=GetWidth()*(sc.x-1)/2.0;
		top+=GetHeight()*(sc.y-1)/2.0; bottom-=GetHeight()*(sc.y-1)/2.0;};

	//! intersect a and b
	void Intersect( const CPGLRect<T>& a, const CPGLRect<T>& b, bool yDown = true)
	{
		left=__max(a.left, b.left); right=__min(a.right, b.right);
		if (yDown)
		{top=__max(a.top, b.top); bottom=__min(a.bottom, b.bottom);}
		else
		{top=__min(a.top, b.top); bottom=__max(a.bottom, b.bottom);}
	}
	//@}
};

/*! CPGLRect<double> CPGLRectD
Rect of double type

  \ingroup PGLBasicGroup
*/
typedef CPGLRect<double> CPGLRectD; 
/*! CPGLRect<int> CPGLRectI
Rect of int type

  \ingroup PGLBasicGroup
*/
typedef CPGLRect<int> CPGLRectI; 
/*! CPGLRect<UINT> CPGLRectU
Rect of UINT type

  \ingroup PGLBasicGroup
*/
typedef CPGLRect<UINT> CPGLRectU; 
/*! CPGLRect<bool> CPGLRectB
Rect of bool type

  \ingroup PGLBasicGroup
*/
typedef CPGLRect<bool> CPGLRectB; 
/*! CPGLRect<float> CPGLRectF
Rect of float type

  \ingroup PGLBasicGroup
*/
typedef CPGLRect<float> CPGLRectF; 

class ScopedWindowDC
{
public:
	ScopedWindowDC( CWnd* pWnd_ )
		:m_pWnd(pWnd_),m_pDC(NULL)
	{
		if (m_pWnd)
			m_pDC = m_pWnd->GetWindowDC();
	}
	~ScopedWindowDC()
	{
		if (m_pWnd && m_pDC)
			m_pWnd->ReleaseDC(m_pDC);
	}

	CDC* GetDC()			{	ASSERT(m_pDC);	return m_pDC;};
	operator bool() const	{	return m_pDC != NULL;};
private:
	CDC* m_pDC;
	CWnd* m_pWnd;
};

#endif // !defined(AFX_PGLGLUTILITY_H__0E205062_3FFE_4548_9974_C5136B8D6580__INCLUDED_)

